package zack.gateway.assist.config;


import io.netty.channel.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import redis.clients.jedis.JedisPoolConfig;
import zack.gateway.assist.application.GatewayApplication;
import zack.gateway.assist.domain.service.GatewayCenterService;
import zack.gateway.core.session.Configuration;
import zack.gateway.core.session.defaults.DefaultGatewaySessionFactory;
import zack.gateway.core.socket.GatewaySocketServer;

import java.net.ServerSocket;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author A1793
 */
@EnableConfigurationProperties(GatewayServiceProperties.class)
public class GatewayAutoConfig {

    private Logger logger = LoggerFactory.getLogger(GatewayAutoConfig.class);


    @Bean
    public GatewayCenterService registerGatewayService() {
        return new GatewayCenterService();
    }

    @Bean
    public GatewayApplication gatewayApplication(GatewayServiceProperties properties,
                                                 GatewayCenterService gatewayCenterService,
                                                 Configuration configuration,
                                                 Channel channel) {
        return new GatewayApplication(properties, gatewayCenterService,configuration,channel);
    }
    @Bean
    public Configuration configuration(GatewayServiceProperties properties) {
        Configuration configuration = new Configuration();
        String[] split = properties.getGatewayAddress().split(":");
        configuration.setHost(split[0]);
        configuration.setPort(Integer.parseInt(split[1]));
        return configuration;
    }

    @Bean
    public Channel initGateway(Configuration configuration) throws ExecutionException, InterruptedException {
        DefaultGatewaySessionFactory defaultGatewaySessionFactory = new DefaultGatewaySessionFactory(configuration);
        GatewaySocketServer serverSocket = new GatewaySocketServer(configuration, defaultGatewaySessionFactory);
        Future<Channel> future = Executors.newFixedThreadPool(2).submit(serverSocket);
        Channel channel = future.get();
        if (null == channel) {
            throw new RuntimeException("api gateway core netty server start error channel is null");
        }
        while(!channel.isActive()){
            Thread.sleep(500);
        }
        return channel;
    }

    /**
     * 根据注册中心的redis配置创建redis连接
     * @param properties
     * @param gatewayCenterService
     * @return
     */
    @Bean("connectionFactory")
    public RedisConnectionFactory redisConnectionFactory(GatewayServiceProperties properties,GatewayCenterService gatewayCenterService) {
        Map<String, String> redisConfig = gatewayCenterService.queryRedisConfig(properties.getAddress());
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisConfig.get("host"));
        redisStandaloneConfiguration.setPort(Integer.parseInt(redisConfig.get("port")));
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxWaitMillis(30 * 1000);
        poolConfig.setMinIdle(20);
        poolConfig.setMaxIdle(40);
        poolConfig.setTestWhileIdle(true);
        JedisClientConfiguration jedisClientConfiguration = JedisClientConfiguration.builder()
                .connectTimeout(Duration.ofSeconds(30))
                .clientName("api-gateway-assist-redis-" + properties.getGatewayId())
                .usePooling()
                .poolConfig(poolConfig).build();
        return new JedisConnectionFactory(redisStandaloneConfiguration, jedisClientConfiguration);
    }

    /**
     * 设置消息监听
     * @param properties
     * @param redisConnectionFactory
     * @param listenerAdapter
     * @return
     */
    @Bean
    public RedisMessageListenerContainer messageListenerContainer(GatewayServiceProperties properties,
                                                                 @Qualifier("connectionFactory") RedisConnectionFactory redisConnectionFactory,
                                                                  MessageListenerAdapter listenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        container.addMessageListener(listenerAdapter,new PatternTopic(properties.getGatewayId()));
        return container;
    }

    /**
     * 设置监听适配器，当收到信息时调用的方法
     * @param gatewayApplication
     * @return
     */
    @Bean
    public MessageListenerAdapter messageListenerAdapter(GatewayApplication gatewayApplication) {
        return new MessageListenerAdapter(gatewayApplication,"receiveMessage");
    }
}
